<?php
/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link http://www.workerman.net/
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */

/**
 * 用于检测业务代码死循环或者长时间阻塞等问题
 * 如果发现业务卡死，可以将下面declare打开（去掉//注释），并执行php start.php reload
 * 然后观察一段时间workerman.log看是否有process_timeout异常
 */
//declare(ticks=1);


/**
 * 聊天主逻辑
 * 主要是处理 onMessage onClose 
 */
use \GatewayWorker\Lib\Gateway;

require_once 'vendor/mysql-master/src/Connection.php';

class Events
{

    public static $db = null;

    public function __construct()
    {
        //header('Access-Control-Allow-Origin: *');
        //header('Content-Type:application/json; charset=utf-8');
    }

    public static function onWorkerStart()
    {
        // 连接数据库
        $host = '118.89.18.202';
        $port = '3306';
        $user = 'yangpan';
        $password = 'test#A071020';
        $db_name = 'applet';
        self::$db = new Workerman\MySQL\Connection($host, $port, $user, $password, $db_name);
    }

    /**
     * 有消息时
     * @param int $client_id
     * @param mixed $message
     */
    public static function onMessage($client_id, $message)
    {
        // debug
        echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id session:" . json_encode($_SESSION) . " onMessage:" . $message . "\n";
        
        // 客户端传递的是json数据
        $message_data = json_decode($message, true);
        
        if ( ! $message_data) {
            return;
        }
        
        // 根据类型执行不同的业务
        switch ($message_data['type']) {
            // 客户端回应服务端的心跳
            case 'pong':
                return;
            
            // 客户端登录 message格式: {type:login, room_id:1, user_id:1, username:Think, headimgurl:http://} 
            // 添加到客户端，广播给所有客户端xx进入聊天室
            case 'login':
                // 判断是否有房间号                                
                // 房间在后台是否存在
                $res = self::$db->select('id')
                    ->from('applet_hx_classroom')
                    ->where('id=' . $message_data['room_id'])
                    ->row();
                                
                if ( ! $res) {
                    self::err('err_login_failed', '房间号不存在', [], true);
                    return;
                }
                
                // 把房间号、用户ID、昵称、头像放到session中
                $room_id = $message_data['room_id'];
                $user_id = $message_data['user_id'];
                $username = htmlspecialchars($message_data['username']);
                $headimgurl = $message_data['headimgurl'];
                
                // 获取房间内所有用户列表  
                // array('7f0' => array('name'=>'Tom', 'sex'=>1),'7f1' => array('name'=>'Joan', 'sex'=>0))
                $clients_list = Gateway::getClientSessionsByGroup($room_id);
                
                // array(array('name'=>'Tom', 'sex'=>1), array('name'=>'Joan', 'sex'=>0))
                $clients_list = array_values($clients_list);

                $_SESSION['room_id'] = $room_id;
                $_SESSION['user_id'] = $user_id;
                $_SESSION['username'] = $username;
                $_SESSION['headimgurl'] = $headimgurl;
                
                // 转播给当前房间的所有客户端，xx进入聊天室 message {type:login, client_id:xx, name:xx} 
                $currentUserdata = ['user_id'=>$user_id, 'username'=>$username, 'headimgurl'=>$headimgurl];
                
                // 发送给房间内其它用户
                Gateway::sendToGroup($room_id, self::suc('receive_new_user_login', '新用户进入', $currentUserdata));
                
                // 新用户加入房间
                Gateway::joinGroup($client_id, $room_id);
                
                // 给当前用户发送用户列表 
                self::suc('receive_login_user_lists', '用户列表', $clients_list, true);
                
                return;
            
            // 客户端发言 message: {type:in_text, msg:xx}
            case 'send_text':
                self::sendTextMsg($client_id, $message_data, 'receive_text');
                return;
            
            // 发送图片
            case 'send_img':
                self::sendTextMsg($client_id, $message_data, 'receive_img');
                return;
            
            // 发送文件 - mp3、word、excel、pdf、ppt等
            case 'send_file':
                self::sendTextMsg($client_id, $message_data, 'receive_file');
                return;
            
            // 发送特效
            case 'send_effects':
                self::sendTextMsg($client_id, $message_data, 'receive_effects');
                return;
            
            // 发送红包
            case 'send_red_packets':
                self::sendTextMsg($client_id, $message_data, 'receive_red_packets');
                return;
            
            // 跳转小程序
        }
    }

    /**
     * 当客户端断开连接时
     * @param integer $client_id 客户端id
     */
    public static function onClose($client_id)
    {
        // debug
        echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id onClose:''\n";
        
        // 从房间的客户端列表中删除
        if (isset($_SESSION['room_id'])) {
            $room_id = $_SESSION['room_id'];
            $new_message = array('type'=>'logout', 'from_client_id'=>$client_id, 'from_username'=>$_SESSION['username'], 'time'=>date('Y-m-d H:i:s'));
            Gateway::sendToGroup($room_id, json_encode($new_message));
        }
    }

    /**
     * 发送信息给群内用户，并保存数据
     * @param array $message_data   消息
     * @param string $type          类型
     * @throws \Exception
     */
    private static function sendTextMsg($client_id, $message_data, $type)
    {
        // 非法请求
        if ( ! isset($_SESSION['room_id'])) {
            self::err('out_user_not_login', '用户未登陆', [], true);
            throw new \Exception("\$_SESSION['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']}");
            return;
        }
        
        $room_id = $_SESSION['room_id'];
        $user_id = $_SESSION['user_id'];
        $username = $_SESSION['username'];
        $headimgurl = $_SESSION['headimgurl'];
        $msg = nl2br(htmlspecialchars($message_data['msg']));
        
        $msgType = $message_data['type'];
        $type_str = 'text';
        
        if ($msgType == 'send_img') {
            $type_str = 'img';
        } else if ($msgType == 'send_file') {
            // http://api.wei-yong.com/201711/test.mp3
            $file_arr = explode('.', $msg);
            $type_str = end($file_arr);
        } else if ($msgType == 'send_effects') {
            $type_str = 'effects';
        } else if ($msgType == 'send_red_packets') {
            $type_str = 'red';
        } else {
            $type_str = 'text';
        }
        
        // 记录保存到数据库 ???
        $insertData = array(
            'group_id'=>$room_id, 
            'user_id'=>$user_id, 
            'type'=>$type_str, 
            'msg'=>$msg,
            'create_time'=>time()
        );
        
        self::$db->insert('applet_hx_chat_log')->cols($insertData)->query();
        
        // 群聊
        $data = ['user_id'=>$user_id, 'username'=>$username, 'headimgurl'=>$headimgurl, 'msg'=>$msg];
        
        // 发送给群内用户，自己排除
        return Gateway::sendToGroup($room_id, self::suc($type, '发送消息', $data), $client_id);
    }

    /**
     * 成功处理
     * @param string    $type   接口类型
     * @param string    $info   返回的信息
     * @param array     $data   返回的数据
     */
    private static function suc($type, $info, $data = [], $sendToCurrentClient = false)
    {
        $new_message = json_encode(['errcode'=>0, 'type'=>$type, 'info'=>$info, 'data'=>$data]);
        
        if ($sendToCurrentClient) {
            Gateway::sendToCurrentClient($new_message);
        }
        
        return $new_message;
    }

    /**
     * 失败处理
     * @param string    $type   接口类型
     * @param string    $info   返回的信息
     * @param array     $data   返回的数据
     */
    private static function err($type, $info, $data = [], $sendToCurrentClient = false)
    {
        $new_message = json_encode(['errcode'=>1, 'type'=>$type, 'info'=>$info, 'data'=>$data]);
        
        if ($sendToCurrentClient) {
            Gateway::sendToCurrentClient($new_message);
        }
        
        return $new_message;
    }
}
